﻿using UnityEngine;
using Unity.Rendering;
using Unity.Mathematics;
using Jinndev.Modding;
using Jinndev.Rendering2D;

namespace Jinndev.Tile2D {

    public class RenderConfig : SubConfig, IConfigIcon {

        public string texture;
        public string material;
        public Int2 dimension;   // 维度，占用格子的数量和形状，最小1x1
        public Float2 renderSize; // 渲染大小，默认等于dimension，因为图片可能只占格子的一部分大小，比如只占图片格子的下一半，则此值为(1, 0.5)
        public Float2 pivot; // 渲染轴心，默认为(dimension / renderSize / 2)
        public Float2 offset; // 渲染编译，默认(0, 0)
        public RotateType rotate = RotateType.None; // 旋转方式，是直接旋转角度，还是切换uv坐标
        public UVType uvType = UVType.Default; // uv类型，uv坐标的计算方式，特定的uv类型会锁定rotate旋转方式
        public SequenceDefine sequenceDefine; // 仅序列帧动画使用(UVType.SequenceFrame)，定义多个序列信息
        public string sequencePreset; // 内置的序列帧配置预设，覆盖sequenceDefine

        private Texture2D _texture;
        private Material _material;
        private Mesh _mesh;
        private RenderMesh _renderMesh;
        private float4 _atlasTilingOffset = new float4(1, 1, 0, 0);  // _texture在自动合成的大图集中的位置

        public RenderConfig() {
            dimension = new int2(1, 1); // 默认值
            renderSize = new float2(-99, -99); // 代表没有配置
            pivot = new float2(-99, -99); // 代表没有配置
            //anchor = new float2(-99, -99); // 代表没有配置
        }

        protected override void OnInit() {
            InitTransform();

            InitUVDescription();

            InitRenderData();

            if (!AtlasBatcher.enableBatchAtlas) {
                InitRenderer();
            }
        }

        private void InitTransform() {
            // 渲染维度，占X*Y的网格数
            dimension = math.max(dimension, new int2(1, 1));

            // 渲染大小
            if (renderSize.x == -99) {
                renderSize.x = dimension.x;
            }
            if (renderSize.y == -99) {
                renderSize.y = dimension.y;
            }
            renderSize *= TileConst.TileSize;

            // 轴心
            if(pivot.x == -99) {
                pivot.x = dimension.x / renderSize.x * 0.5f;
            }
            if (pivot.y == -99) {
                pivot.y = dimension.y / renderSize.y * 0.5f;
            }
            pivot = math.clamp(pivot, 0, 1) - offset;
        }

        private void InitUVDescription() {
            //if (uvType == UVType.SequenceFrame) {
            //    rotate = RotateType.None;
            //}

            if (uvType == UVType.SequenceFrame) {
                // 尝试加载预设
                if (!string.IsNullOrWhiteSpace(sequencePreset)) {
                    SequencePresets.TryGet(sequencePreset, out sequenceDefine);
                }
                // 矫正数据
                sequenceDefine.dimension = math.max(sequenceDefine.dimension, new int2(1, 1)); // 最小1x1
                sequenceDefine.iconIndex = math.max(0, sequenceDefine.iconIndex);
                sequenceDefine.iconFrame = math.max(0, sequenceDefine.iconFrame);
                if (sequenceDefine.sequences == null) {
                    sequenceDefine.sequences = new Sequence[0];
                }
                for(int i = 0; i < sequenceDefine.sequences.Length; i++) {
                    Sequence sequence = sequenceDefine.sequences[i];
                    sequence.start = math.max(sequence.start, new int2(0, 0)); // 默认从左下角开始
                    sequence.dimension = math.max(sequence.dimension, new int2(1, 1)); // 默认1x1大小
                    sequence.frames = math.max(sequence.frames, 1); // 最少有1帧
                    sequence.fps = sequence.frames == 1 ? 0 : math.max(sequence.fps, 0); // 只有1帧的动画帧率为0fps，即不动
                    sequenceDefine.sequences[i] = sequence;
                }
            }
        }

        private void InitRenderData() {
            _mesh = ResourceManager.GetSharedRectMesh(TileConst.TileMesh, renderSize, pivot);    // 根据size取得单例mesh

            if (!string.IsNullOrWhiteSpace(texture)) {
                texture = texture.Trim();
                _texture = ResourceManager.Load<Texture2D>(Mod.path, texture);
            }
            else {
                Debug.LogError($"Texture config not found");
            }
        }

        public void InitRenderer() {
            if (!string.IsNullOrWhiteSpace(material)) {
                material = material.Trim();
                _material = ResourceManager.GetSharedMaterial(material, _texture);
            }
            else {
                _material = ResourceManager.GetSharedMaterial(ResourceManager.DEFAULT, _texture);
            }

            _renderMesh = new RenderMesh {
                mesh = GetMesh(),
                material = GetMaterial()
            };
        }

        public Config.Icon GetIcon() {
            Config.Icon icon = Base.GetIcon();
            if(icon != null && icon.texture != null) {
                return icon;
            }
            return GetIcon(sequenceDefine.iconIndex, sequenceDefine.iconFrame);
        }

        public Config.Icon GetIcon(int iconIndex, int iconFrame) {
            Texture2D texture = GetTexture();
            float4 tilingOffset;
            if (texture != null && uvType == UVType.SequenceFrame) {
                tilingOffset = GetSequenceTilingOffset(iconIndex, iconFrame);
            }
            else {
                tilingOffset = TileConst.DefaultTilingOffset;
            }
            tilingOffset = CommonUtil.ApplyAtlasTilingOffset(tilingOffset, _atlasTilingOffset);
            Rect rect = CommonUtil.TilingOffsetToRect(tilingOffset);
            return new Config.Icon(texture, rect, tilingOffset, offset);
        }

        public virtual Texture2D GetTexture() {
            return _texture;
        }

        public virtual void SetTexture(Texture2D texture) {
            _texture = texture;
        }

        public virtual Material GetMaterial() {
            return _material;
        }

        public virtual Mesh GetMesh() {
            return _mesh;
        }

        public virtual RenderMesh GetRenderMesh() {
            return _renderMesh;
        }

        /// <summary>
        /// 得到按当前rotate类型和指定direction翻转后的用于显示的实际维度
        /// </summary>
        /// <param name="direction"></param>
        /// <returns></returns>
        public virtual int2 GetRealDimension(int direction) {
            if (rotate != RotateType.None) {
                if (direction == Direction.LEFT || direction == Direction.RIGHT) {
                    return new int2(dimension.y, dimension.x);
                }
            }
            return dimension;
        }

        public virtual float2 GetRealPivot(int direction) {
            if (rotate != RotateType.None) {
                if (direction == Direction.LEFT || direction == Direction.RIGHT) {
                    return new float2(pivot.y, pivot.x);
                }
            }
            return pivot;
        }

        public virtual float2 GetRealRenderSize(int direction) {
            if (rotate != RotateType.None) {
                if (direction == Direction.LEFT || direction == Direction.RIGHT) {
                    return new float2(renderSize.y, renderSize.x);
                }
            }
            return renderSize;
        }

        public virtual float4 GetAtlasTilingOffset() {
            return _atlasTilingOffset;
        }

        public virtual void SetAtlasTilingOffset(float4 atlasTilingOffset) {
            _atlasTilingOffset = atlasTilingOffset;
        }

        /// <summary>
        /// 根据当前自动图集的TilingOffset，创建AtlasTilingOffset
        /// </summary>
        /// <param name="tilingOffset"></param>
        /// <returns></returns>
        public AtlasTilingOffset CreateTilingOffset(float4 tilingOffset) {
            return new AtlasTilingOffset {
                value = tilingOffset,
                atlasTilingOffset = GetAtlasTilingOffset()
            };
        }

        /// <summary>
        /// 根据uvType和旋转类型，得到渲染信息，如果是使用序列帧做旋转的话，默认顺序为上右下左，恰好和Direction的值相等
        /// </summary>
        /// <param name="direction"></param>
        /// <returns></returns>
        public RenderInfo GetRenderInfo(int direction) {
            if(rotate == RotateType.Sequence && uvType == UVType.SequenceFrame) {
                int sequenceIndex = direction;
                if (sequenceIndex >= 0 && sequenceIndex < sequenceDefine.sequences.Length) {
                    return RenderInfo.Create(sequenceIndex, 0, direction);
                }
            }
            return RenderInfo.Create(direction);
        }

        /// <summary>
        /// 得到按当前rotate类型和指定direction旋转后的贴图tiling和offset，适用于单帧图片
        /// </summary>
        /// <param name="direction"></param>
        /// <returns></returns>
        public virtual float4 GetDirectionTilingOffset(int direction) {
            float4 tilingOffset = GetDefaultTilingOffset(direction);
            return tilingOffset;
        }

        /// <summary>
        /// 得到指定序列帧的贴图tiling和offset，适用于多帧图片
        /// </summary>
        /// <param name="sequenceIndex">序列帧编号从0开始</param>
        /// <param name="frame">帧数从0开始</param>
        /// <returns></returns>
        public virtual float4 GetSequenceTilingOffset(int sequenceIndex, int frame) {
            if(uvType != UVType.SequenceFrame) {
                Debug.LogError("Invalid operation");
                return GetDefaultTilingOffset(Direction.UP);
            }
            if(sequenceIndex < 0 || sequenceIndex >= sequenceDefine.sequences.Length) {
                Debug.LogError($"Index out of : {sequenceIndex}/{sequenceDefine.sequences.Length}");
                return GetDefaultTilingOffset(Direction.UP);
            }
            return TileUtil.GetSequenceTilingOffset(sequenceDefine.sequences[sequenceIndex], sequenceDefine.dimension, sequenceDefine.anchor, sequenceDefine.direction, frame);
        }

        // 默认旋转图集
        private float4 GetDefaultTilingOffset(int direction) {
            if (rotate == RotateType.Tiling_HV) {
                // 贴图2x1
                // 水平+垂直
                if (Direction.IsHorizontal(direction)) {
                    return new float4(new float2(0.5f, 1), new float2(0, 0));
                }
                else if (Direction.IsVertical(direction)) {
                    return new float4(new float2(0.5f, 1), new float2(0.5f, 0));
                }
            }
            else if (rotate == RotateType.Tiling_URDL) {
                // 贴图4x1
                // 上 右 下 左
                if (direction == Direction.UP) {
                    return new float4(new float2(0.25f, 1f), new float2(0, 0f));
                }
                else if (direction == Direction.RIGHT) {
                    return new float4(new float2(0.25f, 1f), new float2(0.25f, 0f));
                }
                else if (direction == Direction.DOWN) {
                    return new float4(new float2(0.25f, 1f), new float2(0.5f, 0f));
                }
                else if (direction == Direction.LEFT) {
                    return new float4(new float2(0.25f, 1f), new float2(0.75f, 0f));
                }
            }
            else if (rotate == RotateType.Tiling_H_U_D) {
                // 贴图2x2
                // 上+下
                // 水平+空白
                if (Direction.IsHorizontal(direction)) {
                    return new float4(new float2(0.5f, 0.5f), new float2(0, 0));
                }
                else if (direction == Direction.UP) {
                    return new float4(new float2(0.5f, 0.5f), new float2(0, 0.5f));
                }
                else if (direction == Direction.DOWN) {
                    return new float4(new float2(0.5f, 0.5f), new float2(0.5f, 0.5f));
                }
            }
            else if (rotate == RotateType.Tiling_LR_V) {
                // 贴图2x2
                // 垂直+空白
                // 左+右
                if (direction == Direction.LEFT) {
                    return new float4(new float2(0.5f, 0.5f), new float2(0, 0f));
                }
                else if (direction == Direction.RIGHT) {
                    return new float4(new float2(0.5f, 0.5f), new float2(0.5f, 0f));
                }
                else if (Direction.IsVertical(direction)) {
                    return new float4(new float2(0.5f, 0.5f), new float2(0, 0.5f));
                }
            }
            else if (rotate == RotateType.Tiling_LR_UD) {
                // 贴图2x2
                // 上+下
                // 左+右
                if (direction == Direction.LEFT) {
                    return new float4(new float2(0.5f, 0.5f), new float2(0, 0f));
                }
                else if (direction == Direction.RIGHT) {
                    return new float4(new float2(0.5f, 0.5f), new float2(0.5f, 0f));
                }
                else if (direction == Direction.UP) {
                    return new float4(new float2(0.5f, 0.5f), new float2(0, 0.5f));
                }
                else if (direction == Direction.DOWN) {
                    return new float4(new float2(0.5f, 0.5f), new float2(0.5f, 0.5f));
                }
            }
            // 默认完整贴图
            return new float4(new float2(1, 1), new float2(0, 0));
        }

        // 得到按当前rotate类型和指定direction旋转后的角度
        public virtual float3 GetAngle(int direction) {
            if (rotate == RotateType.Simple) {
                // 只有Simple是直接转角度
                if (direction == Direction.LEFT) {
                    return new float3(0, 0, 90);
                }
                else if (direction == Direction.RIGHT) {
                    return new float3(0, 0, -90);
                }
                else if (direction == Direction.DOWN) {
                    return new float3(0, 0, 180);
                }
                return float3.zero;
            }
            return float3.zero;
        }

        public class Icon {
        }
    }

}
